package com.warm.androidstudy.utils;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.media.ExifInterface;

import androidx.annotation.Nullable;

import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 图片压缩工具类
 * Created by shenyq on 2018/4/12.
 */

public class ImageCompressUtils extends Throwable {

    public ImageCompressUtils() {

    }

    /**
     * 简单的压缩 （根据文件地址）
     *
     * @param oldFilePath
     * @param newSavePath
     * @return
     * @throws Exception
     */
    public static String simpleCompressImage(String oldFilePath, String newSavePath) throws Exception {
        LogUtil.e("压缩图片：原路径 --- ", oldFilePath + "---，新路径" + newSavePath);
        String newImageName;
        CompressFormat CompressImgType = judgeImageType(oldFilePath);
        File file = new File(oldFilePath);
        if (!file.exists()) {
            throw new Exception("找不到要压缩的图片文件");
        } else {
            newImageName = file.getName();
            LogUtil.e("--压缩ImageCompressUtils -- newImageName ：", newImageName);
            Bitmap bitmap;
            FileInputStream fis = new FileInputStream(file);
            int size = (int) (fis.getChannel().size() / 1024L);
            LogUtil.e("原始图片大小为：", size + "kb");
            //1、读取图片的旋转的角度
            int getDegree = readPictureDegree(oldFilePath);
            String newFilePath = newSavePath + newImageName;
            if (size > 1536) {
                //2、压缩图片的大小（只读边不读具体内容，避免造成OOM）
                bitmap = compressImageFromFile(oldFilePath, size);
                //3、修复图片被旋转的角度
                bitmap = rotaingImageView(getDegree, bitmap);
                //4、处理完压缩和旋转后的新图片保存方法
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                bitmap.compress(CompressImgType, 100, baos);
                LogUtil.e("--simpleCompressImage 压缩后图片大小为：", baos.toByteArray().length / 1024 + "kb");
                baostreamToImage(baos, newFilePath);//把文件流写入到某个路径下（复制文件）
                baos.reset();
                baos.close();
                if (bitmap != null && !bitmap.isRecycled()) {
                    bitmap.recycle();
                    bitmap = null;
                }
                return newFilePath;
            } else {
                LogUtil.e("--压缩的图大小 --- 没有超过1.5M，不压缩");
                return oldFilePath;
            }
        }
    }

    /**
     * 根据图片大小按比例缩放
     *
     * @param srcPath
     * @return
     */
    public static Bitmap compressImageFromFile(String srcPath, int size) {
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        newOpts.inJustDecodeBounds = true;//只加载图像框架
        BitmapFactory.decodeFile(srcPath, newOpts);
//        newOpts.inSampleSize = calculateInSampleSize(newOpts, 480, 800);// 计算该图像压缩比例
        newOpts.inSampleSize = calculateScale(size);// 计算该图像压缩比例
        LogUtil.e("---ImageCompressUtils 计算的到压缩比例inSampleSize = " + newOpts.inSampleSize);
        newOpts.inJustDecodeBounds = false; //设置 -- 改回加载全部图像内容
        //避免出现内存溢出的情况，进行相应的属性设置
        newOpts.inPreferredConfig = Bitmap.Config.ARGB_8888;//失真度最少
        newOpts.inPurgeable = true;//当存储Pixel的内存空间在系统内存不足时是否可以被回收
        newOpts.inInputShareable = true;//inPurgeable为true情况下才生效，是否可以共享一个InputStream
//        newOpts.inDither = false;//不进行图片抖动处理
        Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
        return bitmap;
    }

    /**
     * 读取图片的大小（只读边不读具体内容，避免造成OOM）
     *
     * @param srcPath
     * @return
     */
    public static int[] getImageWithHeigh(String srcPath) {
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        newOpts.inJustDecodeBounds = true;//只加载图像框架
        BitmapFactory.decodeFile(srcPath, newOpts);
        newOpts.inJustDecodeBounds = false;
        int width = newOpts.outWidth;
        int height = newOpts.outHeight;
        int[] imageSizeArray = {width, height};//静态初始化并赋值
        return imageSizeArray;
    }

    private static int calculateScale(int size) {
        //自己直接放回大概的缩放值
        if (size < 2500) {
            return 2;
        } else if (size < 4500) {
            return 3;
        } else if (size < 7500) {
            return 4;
        } else if (size < 9000) {
            return 5;
        } else if (size < 13500) {
            return 6;
        } else {
            return 10;
        }
    }

    //计算图片的缩放值
    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
        LogUtil.e("--- ImageCompressUtils -- calculateInSampleSize 计算的到的压缩比例为：" + inSampleSize);
        return inSampleSize;
    }

    /**
     * 读取图片的旋转的角度
     *
     * @param path 图片绝对路径
     * @return 图片的旋转角度
     */
    public static int readPictureDegree(String path) {
        int degree = 0;
        try {
            // 从指定路径下读取图片，并获取其EXIF信息
            ExifInterface exifInterface = new ExifInterface(path);
            // 获取图片的旋转信息
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    /**
     * 旋转图片
     *
     * @param angle  被旋转角度
     * @param bitmap 图片对象
     * @return 旋转后的图片
     */
    public static Bitmap rotaingImageView(int angle, Bitmap bitmap) {
        Bitmap returnBm = null;
        // 根据旋转角度，生成旋转矩阵
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);
        try {
            // 将原始图片按照旋转矩阵进行旋转，并得到新的图片
            returnBm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        } catch (OutOfMemoryError e) {
        }
        if (returnBm == null) {
            returnBm = bitmap;
        }
        if (bitmap != returnBm) {
            bitmap.recycle();
        }
        return returnBm;
    }

    /**
     * 把文件流写入到某个路径下（复制文件）
     *
     * @param baos
     * @param newFilePath
     */
    public static void baostreamToImage(ByteArrayOutputStream baos, String newFilePath) {
        try {
            File e = new File(newFilePath);
            FileOutputStream fos = null;
            fos = new FileOutputStream(e);
            fos.write(baos.toByteArray());
            fos.flush();
            fos.close();
            baos.reset();
            baos.close();
        } catch (FileNotFoundException var4) {
            var4.printStackTrace();
        } catch (IOException var5) {
            var5.printStackTrace();
        }
    }

    public static ByteArrayOutputStream InputStreamTOByteArrayOS(InputStream in) throws IOException {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] data = new byte[4096];
        boolean count = true;

        int count1;
        while ((count1 = in.read(data, 0, 4096)) != -1) {
            outStream.write(data, 0, count1);
        }

        Object data1 = null;
        return outStream;
    }


    public static CompressFormat judgeImageType(String filePath) {
        CompressFormat CompressImgType = CompressFormat.JPEG;
        if (filePath.endsWith(".jpg") || filePath.endsWith(".jpeg")) {
            CompressImgType = CompressFormat.JPEG;
        } else {
            if (filePath.endsWith(".png")) {
                CompressImgType = CompressFormat.PNG;
            } else if (filePath.endsWith(".webp")) {
                CompressImgType = CompressFormat.WEBP;
            } else {
                CompressImgType = CompressFormat.JPEG;
            }
        }
        return CompressImgType;
    }

    public static Bitmap compressBtimap(Bitmap bitmap) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(CompressFormat.JPEG, 100, baos);
        int options = 100;

        while (baos.toByteArray().length / 1024 > 80) {
            baos.reset();
            options -= 10;
            bitmap.compress(CompressFormat.JPEG, options, baos);
        }

        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        Bitmap compressBitmap = BitmapFactory.decodeStream(isBm, (Rect) null, (BitmapFactory.Options) null);
        return compressBitmap;
    }

    /**
     * 压缩图片（保存原图片类型；不改变文件名后缀）
     *
     * @param oldFilePath
     * @param newSavePath
     * @return
     * @throws Exception
     */
    @TargetApi(14)
    public static String compressImage(String oldFilePath, String newSavePath) throws Exception {
        LogUtil.e("原路径 --- ", oldFilePath + " ，新路径 --- " + newSavePath);
        String newImageName;
        CompressFormat CompressImgType = judgeImageType(oldFilePath);
        File file = new File(oldFilePath);
        if (!file.exists()) {
            throw new Exception("找不到要压缩的图片文件");
        } else {
            newImageName = file.getName();
            Bitmap bitmap;
            FileInputStream fis = new FileInputStream(file);
            int size = (int) (fis.getChannel().size() / 1024L);
            LogUtil.e("原始图片大小为：", size + "kb");
            if (size > 2000) {
                bitmap = compressImageFromFile(oldFilePath, size);//读取图片的大小（只读边不读具体内容，避免造成OOM）
            } else {
                bitmap =BitmapUtil.decodeFileToBitmap(oldFilePath);
            }

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            bitmap.compress(CompressImgType, 100, baos);
            int options = 100;

            while (baos.toByteArray().length / 1024 > 1536) {
                baos.reset();
                options -= 10;
                bitmap.compress(CompressImgType, options, baos);
            }

            LogUtil.e("--compressImage 压缩后图片大小为：", baos.toByteArray().length / 1024 + "kb");
            String newFilePath = newSavePath + newImageName;
            baostreamToImage(baos, newFilePath);////把文件流写入到某个路径下（复制文件）
            baos.reset();
            baos.close();
            if (bitmap != null && !bitmap.isRecycled()) {
                bitmap.recycle();
                bitmap = null;
            }
            return newFilePath;
        }
    }

    //通过glide获取图片的宽和高
    public static void getImageWh(Context context, String url, final GetImageData data) {
        //获取图片真正的宽高
        Glide.with(context)
                .asBitmap()//Glide返回一个Bitmap对象
                .load(new MyGlideUrl(url))//取得缓存的图片资源
                .into(new SimpleTarget<Bitmap>() {
                    @Override
                    public void onResourceReady(Bitmap bitmap, Transition<? super Bitmap> transition) {
                        data.sendData(bitmap.getWidth(), bitmap.getHeight());
                    }

                    @Override
                    public void onLoadFailed(@Nullable Drawable errorDrawable) {
                        data.sendData(0, 0);
                        super.onLoadFailed(errorDrawable);
                    }
                });
    }

    public interface GetImageData {
        void sendData(int width, int height);
    }
}